<template>
    <div class="page" v-loading="pageLoading">
        <div class="header">
            <h2>DESeq2 差异分析（RNA-seq）</h2>
            <div class="actions">
                <el-button type="primary" :loading="loading" @click="loadDefault">加载默认结果</el-button>
                <el-upload class="upload" drag action="#" :auto-upload="false" :on-change="onCountsChange" :limit="1">
                    <i class="el-icon-upload"></i>
                    <div class="el-upload__text">上传 counts 文件（CSV/TSV，第一列名为 gene）</div>
                </el-upload>
                <el-upload class="upload" drag action="#" :auto-upload="false" :on-change="onMetaChange" :limit="1">
                    <i class="el-icon-upload"></i>
                    <div class="el-upload__text">上传 meta 文件（CSV/TSV，列含 SampleID, condition）</div>
                </el-upload>
                <el-button type="success" :loading="loading" :disabled="!countsFile || !metaFile" @click="runUpload">
                    运行上传数据分析
                </el-button>
            </div>
            <div v-if="summary" class="summary">
                <span>基因数：{{ summary.n_genes }}</span>
                <span>显著数：{{ summary.n_sig }}</span>
                <span>上调：{{ summary.up }}</span>
                <span>下调：{{ summary.down }}</span>
                <el-button v-if="links" type="primary" link @click="download(links.results_csv, 'result.csv')">
                    下载结果 CSV
                </el-button>
                <el-button v-if="links" type="primary" link @click="download(links.volcano_image, 'volcano.png')">
                    下载火山图 PNG
                </el-button>
                <el-button v-if="links" type="primary" link @click="download(links.zip, 'default.zip')">
                    下载打包 ZIP
                </el-button>
            </div>
        </div>

        <el-row :gutter="16">
            <el-col :span="24">
                <el-card>
                    <template #header>火山图</template>
                    <div ref="chartRef" class="chart"></div>
                </el-card>
            </el-col>
        </el-row>

        <el-row :gutter="16" style="margin-top: 16px">
            <el-col :span="24">
                <el-card>
                    <template #header>差异分析结果</template>
                    <el-table :data="pagedData" height="520" border size="small">
                        <el-table-column prop="gene" label="gene" min-width="160" />
                        <el-table-column prop="baseMean" label="baseMean" min-width="120" />
                        <el-table-column prop="log2FoldChange" label="log2FC" min-width="110" />
                        <el-table-column prop="lfcSE" label="lfcSE" min-width="100" />
                        <el-table-column prop="stat" label="stat" min-width="100" />
                        <el-table-column prop="pvalue" label="pvalue" min-width="120" />
                        <el-table-column prop="padj" label="padj" min-width="120" />
                    </el-table>
                    <div class="pager">
                        <el-pagination
                            background
                            layout="prev, pager, next, jumper"
                            :total="tableData.length"
                            :page-size="pageSize"
                            v-model:current-page="page"
                        />
                    </div>
                </el-card>
            </el-col>
        </el-row>

        <el-dialog
            v-model="progressVisible"
            title="任务执行中"
            :close-on-click-modal="false"
            :show-close="false"
            width="400px"
            >
            <div style="text-align:center; padding: 20px">
                <el-progress :percentage="progress" :status="progressStatus" />
                <p v-if="progress < 100">正在处理，请稍候...</p>
                <p v-else>任务完成！</p>
            </div>
        </el-dialog>
    </div>
</template>

<script setup lang="ts" name="RNASeqtools">
    import { ref, onMounted, watch, computed, nextTick, onBeforeUnmount } from 'vue';
    import * as echarts from 'echarts';
    import { get, post } from '@/axios/api';
    import { download } from '@/common/util';
    import { ElMessage } from 'element-plus';
    import { usePollingTask } from '@/common/usePollingTask';
    import { useRoute, useRouter } from 'vue-router';
    import { loadUser, useAuth } from '@/common/useAuth';

    const { user } = useAuth();
    const router = useRouter()
    const loading = ref(false);
    const chartRef = ref<HTMLDivElement | null>(null);
    let chart: echarts.ECharts | null = null;

    const pageLoading = ref(false);

    const points = ref<any[]>([]);
    const summary = ref<any | null>(null);
    const links = ref<{
        volcano_image: string;
        results_csv: string;
        zip: string;
    } | null>(null);
    const tableData = ref<any[]>([]);

    const page = ref(1);
    const pageSize = 50;
    const pagedData = computed(() => tableData.value.slice((page.value - 1) * pageSize, page.value * pageSize));

    const countsFile = ref<File | null>(null);
    const metaFile = ref<File | null>(null);

    const progressVisible = ref(false);
    const progress = ref(0);
    const progressStatus = ref<"success" | "exception" | undefined>();
    const route = useRoute();


    const { pollTaskStatus, stopPolling } = usePollingTask();


    function onCountsChange(file: any) {
        countsFile.value = file.raw;
    }
    function onMetaChange(file: any) {
        metaFile.value = file.raw;
    }

    async function loadDefault() {
        loading.value = true;
        try {
            const res:any = await get('/rna/deseq2/default/', {});
            if (res && res.task_id) {
                try {
                    const taskId = res.task_id;
                    if (!taskId) {
                        ElMessage.error('Failed to upload');
                    }
                    const apiUrl = `/rna/deseq2/polling/${taskId}/`
                    await pollTaskStatus(
                        apiUrl,
                        result => {
                            // 成功：后端 result 很可能就是你之前 applyResult 需要的对象
                            console.log(result)
                            try {
                                applyResult(result);
                                progress.value = 100;
                                progressStatus.value = 'success';
                                setTimeout(() => {
                                    progressVisible.value = false;
                                }, 1000);
                                pageLoading.value = false;
                                loading.value = false;
                            } catch (e) {
                                console.error('applyResult 处理失败', e);
                            } finally {
                                if (result?.status == 'success' || result?.status == 'failed') {
                                    loading.value = false;
                                }
                            }
                        },
                        err => {
                            console.error('Task failed or polling error:', err);
                            // 如果后端给出了 error 文本，展示
                            ElMessage.error(typeof err === 'string' ? err : '任务执行失败');
                            loading.value = false;
                            progressVisible.value = false;
                        },
                        res => {
                            console.log('Polling task status:', res);
                            progressVisible.value = true
                            progress.value = res.progress;

                        },
                        {
                            initialDelay: 1000,
                            maxDelay: 10000,
                            timeout: 5 * 60 * 1000
                        }
                    );
                } catch (err: any) {
                    console.error('upload failed', err);
                    const msg = err?.response?.data?.detail || err.message || '上传或生成失败';
                    ElMessage.error(msg);
                } 
            }
            applyResult(res);
        } finally {
            loading.value = false;
        }
    }

    async function runUpload() {
        if (!countsFile.value || !metaFile.value) return;
        loading.value = true;
        pageLoading.value = true;
        try {
            const form = new FormData();
            form.append('counts', countsFile.value);
            form.append('meta', metaFile.value);
            const res: any = await post('/rna/deseq2/upload/', form, {
                headers: { 'Content-Type': 'multipart/form-data' },
                timeout: 999999999
            });
            const taskId = res.task_id;
            if (!taskId) {
                ElMessage.error('Failed to upload');
            } else {
                ElMessage.success('任务提交成功，现在将跳转到任务管理页面');
                setTimeout(() => {
                    router.push('/taskpage');
                }, 2000);
            }
            const apiUrl = `/rna/deseq2/polling/${taskId}/`
            // await pollTaskStatus(
            //     apiUrl,
            //     result => {
            //         try {
            //             applyResult(result);
            //             progress.value = 100;
            //             progressStatus.value = 'success';
            //             setTimeout(() => {
            //                 progressVisible.value = false;
            //             }, 1000);
            //             pageLoading.value = false;
            //             loading.value = false;
            //         } catch (e) {
            //             console.error('applyResult 处理失败', e);
            //             ElMessage.error('处理任务结果失败');
            //             progressStatus.value = 'exception';
            //             setTimeout(() => {
            //                 progressVisible.value = false;
            //             }, 1000);
            //         } finally {
            //             if (result?.status == 'success' || result?.status == 'failed') {
            //                 loading.value = false;
            //                 pageLoading.value = false;
            //             }
            //         }
            //     },
            //     err => {
            //         console.error('Task failed or polling error:', err);
            //         // 如果后端给出了 error 文本，展示
            //         ElMessage.error(typeof err === 'string' ? err : '任务执行失败');
            //         loading.value = false;
            //         pageLoading.value = false;
            //     },
            //     res => {
            //         console.log('Polling task status:', res);
            //         progressVisible.value = true
            //         progress.value = res.progress;

            //     },
            //     {
            //         initialDelay: 1000,
            //         maxDelay: 10000,
            //         timeout: 5 * 60 * 1000
            //     }
            // );

            // applyResult(res);
        } catch (err) {
            ElMessage.error(typeof err === 'string' ? err : '任务执行失败');
            loading.value = false;
            pageLoading.value = false;
        }
    }

    function applyResult(res: any) {
        // res: { volcano_image, results_csv, zip, points, summary }
        links.value = {
            volcano_image: res.volcano_image,
            results_csv: res.results_csv,
            zip: res.zip
        };
        summary.value = res.summary;
        points.value = res.points || [];
        // table data：按 padj 排序
        tableData.value = [...points.value]
            .map(d => ({
                gene: d.gene,
                baseMean: d.baseMean,
                log2FoldChange: d.log2FoldChange,
                lfcSE: d.lfcSE,
                stat: d.stat,
                pvalue: d.pvalue,
                padj: d.padj
            }))
            .sort((a, b) => (a.padj ?? Infinity) - (b.padj ?? Infinity));

        nextTick(renderChart);
    }

    function renderChart() {
        if (!chartRef.value) return;
        if (!chart) {
            chart = echarts.init(chartRef.value);
            window.addEventListener('resize', () => chart && chart.resize());
        }
        // 构造散点数据
        const seriesData = points.value.map(d => [d.log2FoldChange, d.negLog10P, d.gene, d.padj, d.pvalue, d.sig]);

        const option: echarts.EChartsOption = {
            tooltip: {
                trigger: 'item',
                formatter: (p: any) => {
                    const [x, y, gene, padj, pv, sig] = p.data;
                    return `
                <div><b>${gene}</b></div>
                <div>log2FC: ${x?.toFixed?.(3)}</div>
                <div>-log10(p): ${y?.toFixed?.(3)}</div>
                <div>padj: ${padj ?? 'NA'}</div>
                <div>pvalue: ${pv ?? 'NA'}</div>
                <div>sig: ${sig}</div>
            `;
                }
            },
            grid: { left: 60, right: 20, top: 30, bottom: 50 },
            xAxis: { name: 'log2FC' },
            yAxis: { name: '-log10(p)' },
            dataZoom: [{ type: 'inside' }, { type: 'slider' }],
            legend: { data: ['ns', 'sig'] },
            series: [
                {
                    name: 'points',
                    type: 'scatter',
                    symbolSize: 5,
                    encode: { x: 0, y: 1 },
                    data: seriesData,
                    itemStyle: {
                        color: (params: any) => (params.data[5] === 'sig' ? '#d62728' : '#a9a9a9')
                    }
                }
            ]
        };
        chart.setOption(option, true);
    }

    async function getTaskResult(taskId: string) {
        loading.value = true;
        try {
            const res:any = await get(`/usertasks/${taskId}/`)
            console.log(res)
            if (res && res.status === 'SUCCESS') {
                applyResult(res.result);
                loading.value = false;
            } 
        } catch (e:any) {
            loading.value = false;
            ElMessage.error(e.message);
        }
    }

    onMounted(async() => {
        await loadUser(); 
        if (!user.value) {
            ElMessage.error('请先登录');
            setTimeout(() => {
                router.push({name: "login"});
            }, 1000)
        } else {
            const p = route.params as any;
            if (p.taskid === 'init') {
                loadDefault()
            } else {
                getTaskResult(p.taskid)
            }
        }
    });

    onBeforeUnmount(() => {
        stopPolling();
    });
</script>

<style scoped>
    .page {
        padding: 16px;
    }
    .header {
        display: grid;
        gap: 12px;
    }
    .actions {
        display: flex;
        gap: 10px;
        flex-wrap: wrap;
        align-items: center;
    }
    .upload {
        width: 260px;
    }
    .summary {
        display: flex;
        gap: 16px;
        align-items: center;
        flex-wrap: wrap;
    }
    .chart {
        width: 100%;
        height: 540px;
    }
    .pager {
        margin-top: 8px;
        display: flex;
        justify-content: flex-end;
    }
</style>
